#include "jpgparse.h"

/**
 * 参考 https://blog.csdn.net/yun_hen/article/details/78135122
 * https://zhuanlan.zhihu.com/p/673817570
 */

static jpgFunc_t jpgFunc[] = {
    {SOI, jpg_SOI},
    {EOI, jpg_EOI},
    {SOF0, jpg_SOF0},
    {SOF1, jpg_SOF1},
    {DHT, jpg_DHT},
    {SOS, jpg_SOS},
    {DQT, jpg_DQT},
    {DRI, jpg_DRI},
    {APP0, jpg_APP0},
    {APPN + 0, jpg_APPN},
    {APPN + 1, jpg_APPN},
    {APPN + 2, jpg_APPN},
    {APPN + 3, jpg_APPN},
    {APPN + 4, jpg_APPN},
    {APPN + 5, jpg_APPN},
    {APPN + 6, jpg_APPN},
    {APPN + 7, jpg_APPN},
    {APPN + 8, jpg_APPN},
    {APPN + 9, jpg_APPN},
    {APPN + 10, jpg_APPN},
    {APPN + 11, jpg_APPN},
    {APPN + 12, jpg_APPN},
    {APPN + 13, jpg_APPN},
    {APPN + 14, jpg_APPN},
    {COM, jpg_COM},
};

int8_t jpg_SOI(uint8_t *data, uint32_t len)
{
    printf("jpg_SOI\n");
}
int8_t jpg_EOI(uint8_t *data, uint32_t len)
{
    printf("jpg_EOI\n");
}
int8_t jpg_SOF0(uint8_t *data, uint32_t len)
{
    jpg_SOF0_t sof0 = {0};
    memcpy(&sof0, data, 9);

    printf("jpg_SOF0 len %d\n", len);

    printf("jpg_SOF0 height %d width %d\n",
           sof0.height,
           sof0.width);

    printf("jpg_SOF0\n");
}
int8_t jpg_SOF1(uint8_t *data, uint32_t len)
{
    printf("jpg_SOF1\n");
}
int8_t jpg_DHT(uint8_t *data, uint32_t len)
{
    printf("jpg_DHT\n");
}
int8_t jpg_SOS(uint8_t *data, uint32_t len)
{
    printf("jpg_SOS\n");
}
int8_t jpg_DQT(uint8_t *data, uint32_t len)
{
    jpg_DQT_t dqt = {0};
    memcpy(&dqt, data, 1);
    printf("jpg_DQT len %d\n", len);

    // 打印结构体大小
    // printf("jpg_DQT size %d\n", sizeof(jpg_DQT_t));

    printf("jpg_DQT qtType %d qtNumber %d \n",
           dqt.qtInfo.qtType & 0xF0 >> 4,
           dqt.qtInfo.qtNumber & 0xf0);

    dqt.qtPrecision = (uint8_t *)malloc(len - 1);
    if (dqt.qtPrecision == NULL)
    {
        printf("jpg_DQT malloc fail\n");
        return -1;
    }

    memcpy(dqt.qtPrecision, data + 1, len - 1);

    // 输出精度量化表
    printf("jpg_DQT qtPrecision \n");
    for (int i = 0; i < len - 1; i++)
    {
        printf("%#x ", dqt.qtPrecision[i]);
    }
    printf("\n");

    // 释放内存
    free(dqt.qtPrecision);
    dqt.qtPrecision = NULL;

    printf("jpg_DQT\n");
}
int8_t jpg_DRI(uint8_t *data, uint32_t len)
{
    printf("jpg_DRI\n");
}
int8_t jpg_APP0(uint8_t *data, uint32_t len)
{
    jpg_APP0_t app0 = {0};

    // 打印结构体大小
    // printf("jpg_APP0 size %d\n", sizeof(jpg_APP0_t));

    memcpy(&app0, data, sizeof(jpg_APP0_t));
    // uint8_t format[5];  // 交换格式
    //     uint8_t major;      // 主版本号
    //     uint8_t minor;      // 次版本号
    //     uint8_t unit;       // 密度单位
    //     uint16_t xdensity;  // X像素密度
    //     uint16_t ydensity;  // Y像素密度
    //     uint8_t xthumb;     // 缩略图X像素
    //     uint8_t ythumb;     // 缩略图Y像素
    //     uint8_t *thumbData; // 缩略图数据

    // 一个坑 先右移再左移会有问题 例如下面的的写成 ((0x1234 << 8) & 0xFF00) | ((0x1234 >> 8) & 0xFF)
    // 和 ((le >> 8) & 0xFF) | (app0.xdensity << 8 & 0xFF00) 结果是不一样的

    // uint16_t le = 0;
    // le = app0.xdensity;
    // le = ((le >> 8) & 0xFF) | (app0.xdensity << 8 & 0xFF00);
    // app0.xdensity = le;
    // le = app0.ydensity;
    // le = ((le >> 8) & 0xFF) | (app0.ydensity << 8 & 0xFF00);
    // app0.ydensity = le;
    printf("jpg_APP0 format %s major %d minor %d unit %d xdensity %d ydensity %d xthumb %d ythumb %d\n",
           app0.format,
           app0.major,
           app0.minor,
           app0.unit,
           app0.xdensity >> 8 & 0xFF | app0.xdensity << 8 & 0xFF00,
           app0.ydensity >> 8 & 0xFF | app0.ydensity << 8 & 0xFF00,
           app0.xthumb,
           app0.ythumb);

    // 存在缩略图
    if (app0.xthumb || app0.ythumb)
    {
        printf("jpg_APP0 thumbData %d\n", app0.xthumb * app0.ythumb * 3);
        app0.thumbData = (uint8_t *)malloc(app0.xthumb * app0.ythumb * 3);
        if (app0.thumbData == NULL)
        {
            printf("jpg_APP0 malloc fail\n");
            return -1;
        }

        // 缩略图数据,跳过APP0的14字节
        memcpy(app0.thumbData, data + 14, app0.xthumb * app0.ythumb * 3);

        // 打印缩略图数据
        // if (app0.thumbData != NULL)
        // {
        //     for (int i = 0; i < app0.xthumb * app0.ythumb * 3; i++)
        //     {
        //         printf("%#x ", app0.thumbData[i]);
        //     }
        //     printf("\n");
        // }

        // 释放缩略图数据
        free(app0.thumbData);
        app0.thumbData = NULL;
    }

    printf("jpg_APP0\n");
}
int8_t jpg_APPN(uint8_t *data, uint32_t len)
{
    printf("jpg_APPN\n");
}
int8_t jpg_COM(uint8_t *data, uint32_t len)
{
    printf("jpg_COM\n");
}

//
int8_t jpgParse(uint8_t *fileAddr)
{
    FILE *file = NULL;
    file = fopen(fileAddr, "rb");
    if (file == NULL)
    {
        printf("MAIN open file fail\n");
        return -1;
    }

    fseek(file, 0, SEEK_SET);

    jpg_head_t jpgHead = {0};

    fread(&jpgHead, 1, sizeof(jpgHead), file);

    // 解析文件头
    if (jpgHead.flag != 0xFF || jpgHead.type != SOI)
    {
        printf("jpg head error!\n");
        return -1;
    }

    // 拆解文件结构
    do
    {
        //
        jpg_segment_t jpgSegment = {0};
        // printf("jpgSegment %d\n", sizeof(jpg_segment_t));
        fread(&jpgSegment, 1, 4, file);

        // 打印输出文件信息
        printf("flag %#x type %#X ", jpgSegment.head.flag, jpgSegment.head.type);

        // 检测文件结束
        if (jpgSegment.head.type == EOI || jpgSegment.head.flag == 0 || jpgSegment.head.flag != 0xFF)
        {
            printf("jpg end! index %#x\n", ftell(file));
            break;
        }

        int len = ((jpgSegment.length >> 8 & 0xff) | (jpgSegment.length << 8 & 0xFF00)) - 2;
        printf("len %#x %#x %d index %#x\n", jpgSegment.length, len, len, ftell(file));

        jpgSegment.data = (uint8_t *)malloc(len);
        if (jpgSegment.data == NULL)
        {
            printf("malloc fail!\n");
            return -1;
        }

        memset(jpgSegment.data, 0, len);
        fread(jpgSegment.data, 1, len, file);

        // 打印输出文件数据
        // for (int i = 0; i < jpgSegment.length; i++)
        // {
        //     printf("%02X ", jpgSegment.data[i]);
        // }
        // printf("\n");

        // 所有块二次解析
        int funcLen = sizeof(jpgFunc) / sizeof(jpgFunc[0]);
        for (int i = 0; i < funcLen; i++)
        {
            if (jpgFunc[i].type == jpgSegment.head.type)
            {
                if (jpgFunc[i].cb != NULL)
                {
                    jpgFunc[i].cb(jpgSegment.data, len);
                    break;
                }
            }
        }

        // 未被解析的类型
        // printf(">> unparse type %#x\n", jpgSegment.head.type);

        // 释放内存
        free(jpgSegment.data);

    } while (1);

    printf("parse ok!\n");
    fclose(file);
    return 0;
}

int main(int argc, char *argv[])
{
    printf("param count %d\n", argc);
    for (int i = 0; i < argc; i++)
    {
        printf("param[%d] %s\n", i, argv[i]);
    }

    if (argc < 2)
    {
        printf("This tool is only used to parse jpg files, and is very basic, for reference only\n");
        printf("Usage is as follows: *.exe *.jpg\n");
        return 0;
    }

    if ((strcmp(argv[1], "help") == 0) || (strcmp(argv[1], "-h") == 0))
    {
        printf("This tool is only used to parse jpg files, and is very basic, for reference only\n");
        printf("Usage is as follows: *.exe *.jpg\n");
        return 0;
    }

    jpgParse(argv[1]);
    return 0;
}
